home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / telecomm / sticpsrc.lzh / SOURCE.ARC / UNIX.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-12  |  17.9 KB  |  872 lines

  1. /* OS- and machine-dependent stuff for UNIX */
  2. /* collected from a lot of other stuff from different releases of the package */
  3. /* Written by Mikel Matthews, N9DVG */
  4. /* SYS5 stuff added by Jere Sandidge, K4FUM */
  5. /* cleanup and adaption into NETCHL by PE1CHL */
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <termio.h>
  12. #include <sys/types.h>
  13. #include <sys/times.h>
  14. #include <sys/ndir.h>
  15. #include <sys/select.h>
  16. #include <sys/stat.h>
  17. #include <prototypes.h>
  18.  
  19. #include "global.h"
  20. #include "config.h"
  21. #include "mbuf.h"
  22. #include "internet.h"
  23. #include "iface.h"
  24. #include "cmdparse.h"
  25. #include "timer.h"
  26. #include "environ.h"
  27. #include "asy.h"
  28. #include "unix.h"
  29.  
  30. #ifndef B19200
  31. #define B19200    EXTA
  32. #endif
  33.  
  34. #ifndef B38400
  35. #define B38400    EXTB
  36. #endif
  37.  
  38. #if (defined(FD_SETSIZE) && !defined(M_I86MM))
  39. #define SELECT                /* we can use the select() call */
  40.  
  41. # ifdef FD_ZERO
  42. #  define bzero(s,n)    memset(s,0,n)    /* there is no bzero() in the lib! */
  43. #  define NUL_SET    {0}
  44. # else
  45. typedef unsigned long fd_set;        /* equivalents of FD_xxx macros */
  46. #  define FD_ZERO(fdsp)        *(fdsp) = 0
  47. #  define FD_SET(fd,fdsp)    *(fdsp) |= (1 << (fd))
  48. #  define FD_CLR(fd,fdsp)    *(fdsp) &= ~(1 << (fd))
  49. #  define FD_ISSET(fd,fdsp)    (*(fdsp) & (1 << (fd)))
  50. #  define NUL_SET    0
  51. # endif
  52. #endif
  53.  
  54. struct asy asy[ASY_MAX];
  55. struct interface *ifaces;
  56.  
  57. unsigned nasy = 0;            /* number of ASY interfaces */
  58.  
  59. #ifdef SERVERS
  60. extern FILE *logfp;            /* log file pointer */
  61. extern char logname[];            /* log file name */
  62. #endif
  63.  
  64. #ifdef TRACE
  65. extern FILE *trfp;            /* trace file pointer */
  66. extern char trname[];            /* trace file name */
  67. #endif
  68.  
  69. #ifdef IP
  70. extern struct mbuf *loopq;
  71. #endif
  72. #ifdef AX25
  73. extern struct mbuf *axloopq;
  74. #endif
  75.  
  76. static struct termio saved_termio;    /* termio on program startup */
  77. static struct termio our_termio;    /* termio during program run */
  78.  
  79. #ifdef SELECT
  80. static char *envselect;            /* options passed using SELECT envvar */
  81. static int noselect = 0;        /* # of fd's NOT supporting select */
  82. static int maxfd = 0;            /* # of fd's for select() */
  83. static fd_set port_set = NUL_SET;    /* set containing all serial devices */
  84. static fd_set read_set = NUL_SET;    /* returned set from last select() */
  85. static prg_busy = 0;            /* set when busy */
  86. #endif
  87.  
  88. static char ttbuf[BUFSIZ];        /* buffer used for stdout buffering */
  89.  
  90. /* Called at startup time to set up console I/O */
  91. ioinit()
  92. {
  93. #ifdef SELECT
  94.     fd_set fdset;            /* trial set for select */
  95.     struct timeval timeout;
  96. #endif
  97.  
  98.     setbuf(stdout,ttbuf);        /* buffering for stdout */
  99.  
  100.     tzset();            /* init the timezone variable */
  101.  
  102.     ioctl(0,TCGETA,&saved_termio);    /* read and save termio state */
  103.  
  104.     /* copy termio and drop input processing, echo, and INTR signal */
  105.     /* the VMIN/VTIME will be set up for immediate return when no key */
  106.  
  107.     ASSIGN(our_termio,saved_termio);
  108.     our_termio.c_lflag &= ~(ICANON|ECHO);
  109.     our_termio.c_cc[VINTR] = 0xff;
  110.     our_termio.c_cc[VMIN] = 0;
  111.     our_termio.c_cc[VTIME] = 0;
  112.  
  113. #ifdef SELECT
  114.     envselect = getnenv("SELECT");    /* get SELECT var settings */
  115.  
  116.     if (strchr(envselect,'k') != NULL)    /* select() on keyboard? */
  117.     {
  118.         /* check if stdin can use select() */
  119.  
  120.         FD_ZERO(&fdset);        /* setup an fd_set for stdin */
  121.         FD_SET(0,&fdset);
  122.         timeout.tv_sec = timeout.tv_usec = 0;
  123.  
  124.         if (select(1,&fdset,NULL,NULL,&timeout) < 0)
  125.         {
  126.             if (errno == EINVAL)    /* no select() support */
  127.                 printf("warning: stdin device does not support select()\n");
  128.             else
  129.                 perror("stdin select");
  130.  
  131.             noselect++;
  132.         }
  133.         else            /* select() went okay */
  134.         {
  135.             maxfd = 1;    /* select on fd #0 */
  136.             FD_SET(0,&port_set); /* enter stdin in the select set */
  137.             our_termio.c_cc[VMIN] = 1; /* can wait on read() */
  138.             our_termio.c_cc[VTIME] = 2;
  139.         }
  140.     }
  141.     else
  142.         noselect++;        /* no select on stdin */
  143. #endif
  144.  
  145.     ioctl(0,TCSETA,&our_termio);    /* set our termio values */
  146. }
  147.  
  148. /* Called just before exiting to restore console state */
  149. iostop()
  150. {
  151.     while(ifaces != NULLIF){
  152.         /* first flush the interface's buffers */
  153.         while(ifaces->recv != NULLVFP && (*ifaces->recv)(ifaces))
  154.             ;
  155.         if(ifaces->stop != NULLFP)
  156.             (*ifaces->stop)(ifaces);
  157.         ifaces = ifaces->next;
  158.     }
  159.  
  160.     ioctl(0,TCSETAW,&saved_termio); /* reset to original state */
  161. }
  162.  
  163. /* Spawn subshell */
  164. doshell(argc,argv)
  165. int argc;
  166. char *argv[];
  167. {
  168.     char *command,**envp;
  169.     int ret;
  170.  
  171. #ifdef SERVERS
  172.     if (logfp != NULLFILE)        /* logging to file? */
  173.         fclose(logfp);        /* close the logfile */
  174. #endif
  175.  
  176. #ifdef TRACE
  177.     if (trfp != stdout)        /* trace to file? */
  178.         fclose(trfp);        /* close it during shell exec */
  179. #endif
  180.  
  181.     fflush(stdout);
  182.  
  183.     ioctl(0,TCSETAW,&saved_termio);    /* set original terminal mode */
  184.  
  185.     if((command = getenv("SHELL")) == NULLCHAR)
  186.         command = "/bin/sh";    /* default command interpreter */
  187.  
  188.     envp = make_env();        /* create envinronment array */
  189.  
  190.     switch (fork())            /* spawn a subprocess */
  191.     {
  192.     case -1:            /* an error occurred... */
  193.         perror("fork");
  194.         ret = -1;
  195.         break;
  196.     case 0:                /* this is the child */
  197.         execve(command,argv,envp);
  198.         perror(command);
  199.         exit(1);
  200.     default:            /* this is the parent */
  201.         wait(&ret);        /* wait for child to terminate */
  202.         break;
  203.     }
  204.  
  205.     ioctl(0,TCSETAW,&our_termio);    /* our terminal mode again */
  206.  
  207.     free_env();            /* free the envp and temp env */
  208.  
  209. #ifdef SERVERS
  210.     if (logfp != NULLFILE)        /* re-open logfile if it was open */
  211.         logfp = fopen(logname,"a+");
  212. #endif
  213.  
  214. #ifdef TRACE
  215.     if (trfp != stdout)        /* re-open tracefile if not stdout */
  216.         if ((trfp = fopen(trname,"a+")) == NULLFILE)
  217.         trfp = stdout;
  218. #endif
  219.  
  220.     if (ret != 0)
  221.         return -1;
  222.  
  223.     return 0;
  224. }
  225.  
  226. /* checks the time then ticks and updates ISS */
  227. static time_t clkval = 0;
  228. void
  229. check_time()
  230. {
  231.     int32 iss();
  232.     time_t ntime;
  233.     int maxticks = SEC2TICK(15);    /* upper limit on delayed ticks */
  234.     struct tms tms;            /* dummy required by times() */
  235.  
  236.     if(clkval == 0){
  237.         /* Executed only once */
  238.         clkval = times(&tms);
  239.         return;
  240.     }
  241.  
  242.     ntime = times(&tms);        /* read elapsed time */
  243.  
  244.     while(ntime != clkval){        /* Handle possibility of several missed ticks */
  245. #ifdef IP
  246.         icmpclk();        /* Call this one before tick */
  247. #endif
  248.         tick();
  249. #ifdef IP
  250.         (void)iss();
  251. #endif
  252.         if(maxticks--)        /* check limit on ticks to handle */
  253.             clkval++;
  254.         else
  255.             clkval = ntime; /* ignore any remaining ticks */
  256.     }
  257. }
  258.  
  259. /* Read characters from the keyboard, translating them to internal codes.
  260.  * If none are ready, return -1
  261.  * This piece of code crudely assumes that you are on an ANSI terminal...
  262.  */
  263. int
  264. kbread()
  265. {
  266.     int c;
  267. #ifdef SELECT
  268.     struct timeval timeout;
  269.  
  270.     if (stdin->_cnt == 0 &&        /* no buffered characters? */
  271.             maxfd > 0)            /* select() allowed? */
  272.     {
  273.         read_set = port_set;
  274.         timeout.tv_sec = timeout.tv_usec = 0;
  275.  
  276. #ifdef IP
  277.         if (loopq == NULLBUF)    /* nothing on IP loopback? */
  278. #endif
  279. #ifdef AX25
  280.         if (axloopq == NULLBUF)    /* nothing on AX.25 loopb? */
  281. #endif
  282.  
  283.         if (noselect || prg_busy) /* reason to stay awake? */
  284.             timeout.tv_usec = 20000; /* short sleeptime */
  285.         else
  286.             timeout.tv_sec = 1; /* sleep for a long time */
  287.  
  288.         prg_busy = 1;        /* assume we are busy */
  289.  
  290.         if (select(maxfd,&read_set,NULL,NULL,&timeout) >= 0)
  291.         {
  292. #ifdef DEBUG
  293.             int i;
  294.  
  295.             printf("select:");
  296.             for (i = 0; i < maxfd; i++)
  297.                 if (FD_ISSET(i,&read_set))
  298.                     printf(" %d",i);
  299.             printf("\n");
  300.             fflush(stdout);
  301. #endif
  302.         }
  303.         else
  304.         {
  305. #ifdef DEBUG
  306.             perror("select:");
  307. #endif
  308.  
  309.             return -1;    /* error in select() */
  310.         }
  311.  
  312.         if (FD_ISSET(0,&port_set) && !FD_ISSET(0,&read_set))
  313.             return -1;    /* select() says no input available */
  314.     }
  315. #endif
  316.  
  317.     if((c = getchar()) == EOF)
  318.         return -1;        /* no input available */
  319.  
  320.     if(c == 0x1b){            /* ESC character? */
  321.         /* Lead-in to a special char */
  322.         if(getchar() != '[')
  323.             return 0x1b;
  324.  
  325.         switch(c = getchar())
  326.         {
  327.         case 'M':        /* F-1 key */
  328.             c = -11;
  329.             break;
  330.         case 'N':        /* F-2 key */
  331.             c = -10;
  332.             break;
  333.         case 'O':        /* F-3 key */
  334.             c = -9;
  335.             break;
  336.         case 'P':        /* F-4 key */
  337.             c = -8;
  338.             break;
  339.         case 'Q':        /* F-5 key */
  340.             c = -7;
  341.             break;
  342.         case 'R':        /* F-6 key */
  343.             c = -6;
  344.             break;
  345.         case 'S':        /* F-7 key */
  346.             c = -5;
  347.             break;
  348.         case 'T':        /* F-8 key */
  349.             c = -4;
  350.             break;
  351.         case 'U':        /* F-9 key */
  352.             c = -3;
  353.             break;
  354.         case 'V':        /* F-10 key */
  355.             c = -2;
  356.             break;
  357.         case 'H':        /* HOME key */
  358.             c = -20;
  359.             break;
  360.         case 'A':        /* UP arrow */
  361.             c = -19;
  362.             break;
  363.         case 'I':        /* PAGE UP */
  364.             c = -18;
  365.             break;
  366.         case 'D':        /* LEFT arrow */
  367.             c = -17;
  368.             break;
  369.         case 'C':        /* RIGHT arrow */
  370.             c = -16;
  371.             break;
  372.         case 'F':        /* END key */
  373.             c = -15;
  374.             break;
  375.         case 'B':        /* DOWN arrow */
  376.             c = -14;
  377.             break;
  378.         case 'G':        /* PAGE DOWN */
  379.             c = -13;
  380.             break;
  381.         case 'L':        /* INS key */
  382.             c = -12;
  383.             break;
  384.         default:        /* Dunno what it is */
  385.             c = -1;
  386.         }
  387.     }
  388.     return c;
  389. }
  390.  
  391. /* Create a directory listing in a temp file and return the resulting file
  392.  * descriptor. If full == 1, give a full listing; else return just a list
  393.  * of names.
  394.  */
  395. FILE *
  396. dir(path,full)
  397. char *path;
  398. int full;
  399. {
  400.     char *tname;
  401.     char *option;
  402.     FILE *fp;
  403.     char command[256];
  404.  
  405.     if ((tname = tmpnam(NULLCHAR)) == NULLCHAR)
  406.         return NULLFILE;
  407.  
  408.     if (full < 0)
  409.         option = "C";
  410.     else
  411.         if (full > 0)
  412.             option = "l";
  413.         else
  414.             option = "1";
  415.  
  416.     sprintf(command,"ls -%s \"%s\" >%s",option,path,tname);
  417.     system(command);
  418.     fp = fopen(tname,"r");
  419.     unlink(tname);            /* unlink the file now, it remains open */
  420.  
  421.     return fp;
  422. }
  423.  
  424. /* wildcard filename lookup */
  425. filedir(name,times,ret_str)
  426. char *name;
  427. int times;
  428. char *ret_str;
  429. {
  430.     static char dname[128], fname[128];
  431.     static DIR *dirp = NULL;
  432.     struct direct *dp;
  433.     struct stat sbuf;
  434.     char *cp, temp[128];
  435.  
  436.     /*
  437.      * Make sure that the \0 is there in case we don't find anything
  438.      */
  439.     ret_str[0] = '\0';
  440.  
  441.     if (times == 0) {
  442.         /* default a null name to * */
  443.         if (name == NULL || *name == '\0')
  444.             name = "*";
  445.         /* split path into directory and filename */
  446.         if ((cp = strrchr(name,'/')) == NULL) {
  447.             strcpy(dname,".");
  448.             strcpy(fname,name);
  449.         } else {
  450.             strcpy(dname,name);
  451.             dname[cp - name] = '\0';
  452.             strcpy(fname,cp + 1);
  453.             /* root directory */
  454.             if (dname[0] == '\0')
  455.                 strcpy(dname,"/");
  456.             /* trailing '/' */
  457.             if (fname[0] == '\0')
  458.                 strcpy(fname,"*");
  459.         }
  460.         /* close directory left over from another call */
  461.         if (dirp != NULL)
  462.             closedir(dirp);
  463.         /* open directory */
  464.         if ((dirp = opendir(dname)) == NULL)
  465.             return;
  466.     } else {
  467.         /* for people who don't check return values */
  468.         if (dirp == NULL)
  469.             return;
  470.     }
  471.  
  472.     /* scan directory */
  473.     while ((dp = readdir(dirp)) != NULL) {
  474.         /* test for name match */
  475.         if (wildmat(dp->d_name,fname)) {
  476.             /* test for regular file */
  477.             sprintf(temp,"%s/%s",dname,dp->d_name);
  478.             if (stat(temp,&sbuf) < 0)
  479.                 continue;
  480.             if ((sbuf.st_mode & S_IFMT) != S_IFREG)
  481.                 continue;
  482.             strcpy(ret_str,dp->d_name);
  483.             break;
  484.         }
  485.     }
  486.  
  487.     /* close directory if we hit the end */
  488.     if (dp == NULL) {
  489.         closedir(dirp);
  490.         dirp = NULL;
  491.     }
  492. }
  493.  
  494. /* Initialize asynch port "dev" */
  495. int
  496. asy_init(dev,arg1,arg2,bufsize)
  497. int16 dev;
  498. char *arg1,*arg2;    /* Attach args for address and vector */
  499. unsigned bufsize;
  500. {
  501.     register struct asy *ap;
  502.     struct termio sgttyb;
  503. #ifdef SELECT
  504.     fd_set fdset;            /* trial set for select */
  505.     struct timeval timeout;
  506. #endif
  507.  
  508.     if (dev >= nasy)
  509.         return -1;
  510.  
  511.     ap = &asy[dev];
  512.  
  513.     if ((ap->fd = open(arg1,O_RDWR,0)) < 0) {
  514.         perror(arg1);
  515.         return -1;
  516.     }
  517.  
  518.     /*
  519.      * when possible, close the port upon exec
  520.      */
  521.  
  522.     fcntl(ap->fd,F_SETFD,1);
  523.  
  524.     /*
  525.      * get the termio structure and save it
  526.      */
  527.  
  528.     if (ioctl(ap->fd,TCGETA,&ap->orgmodes) < 0) {
  529.         perror(arg1);
  530.         return -1;
  531.     }
  532.  
  533.     ASSIGN(sgttyb,ap->orgmodes);
  534.  
  535.     sgttyb.c_iflag = IGNBRK|IGNPAR;        /* KISS/SLIP setup */
  536.     sgttyb.c_oflag = 0;
  537.     sgttyb.c_cflag = B9600|CS8|CREAD|CLOCAL; /* default to 9600 baud */
  538.     sgttyb.c_lflag = 0;
  539.     sgttyb.c_cc[VTIME] = 0;
  540.     sgttyb.c_cc[VMIN] = 0;
  541.  
  542. #ifdef CTSFLOW
  543.     if (strchr(arg2,'c') != NULL)    /* CTSFLOW? */
  544.         sgttyb.c_cflag |= CTSFLOW;
  545.  
  546.     if (strchr(arg2,'r') != NULL)    /* RTSFLOW? */
  547.         sgttyb.c_cflag |= RTSFLOW;
  548. #endif
  549.  
  550. #ifdef SELECT
  551.     if (strchr(envselect,'t') != NULL) /* select() on ttys? */
  552.     {
  553.         /* check if this device supports select() */
  554.  
  555.         FD_ZERO(&fdset);    /* setup an fd_set for this port */
  556.         FD_SET(ap->fd,&fdset);
  557.         timeout.tv_sec = timeout.tv_usec = 0;
  558.  
  559.         if (select(ap->fd + 1,&fdset,NULL,NULL,&timeout) < 0)
  560.         {
  561.             if (errno == EINVAL)    /* no select() support */
  562.                 printf("warning: \"%s\" does not support select()\n",arg1);
  563.             else
  564.                 perror(arg1);
  565.  
  566.             noselect++;
  567.         }
  568.         else
  569.         {
  570.             if (ap->fd >= maxfd)
  571.                 maxfd = ap->fd + 1;
  572.  
  573.             FD_SET(ap->fd,&port_set);
  574.             sgttyb.c_cc[VMIN] = 1;    /* read() can block on it */
  575.             sgttyb.c_cc[VTIME] = 2;
  576.         }
  577.     }
  578.     else
  579.         noselect++;        /* yet another one without select() */
  580. #endif
  581.  
  582.     if (ioctl(ap->fd,TCSETAF,&sgttyb) < 0) {
  583.         perror(arg1);
  584.         return -1;
  585.     }
  586.  
  587.     ap->tty = malloc(strlen(arg1)+1); /* keep device name */
  588.     strcpy(ap->tty,arg1);
  589.  
  590.     ap->buf = malloc(ap->bufsize = bufsize); /* receive buffer */
  591.  
  592.     return 0;
  593. }
  594. int
  595. asy_stop(iface)
  596. struct interface *iface;
  597. {
  598.     register struct asy *ap;
  599.  
  600.     ap = &asy[iface->dev];
  601.  
  602.     if (ap->fd > 2)            /* sanity check */
  603.         ioctl(ap->fd,TCSETAW,&ap->orgmodes); /* restore tty state */
  604.  
  605.     close(ap->fd);
  606. }
  607. /* Asynchronous line I/O control */
  608. asy_ioctl(interface,argc,argv)
  609. struct interface *interface;
  610. int argc;
  611. char *argv[];
  612. {
  613.     if (argc < 1) {
  614.         printf("%u\n",asy[interface->dev].speed);
  615.         return 0;
  616.     }
  617.  
  618.     return asy_speed(interface->dev,atoi(argv[0]));
  619. }
  620. /* Set asynch line speed */
  621. int
  622. asy_speed(dev,speed)
  623. int16 dev;
  624. int speed;
  625. {
  626.     struct termio sgttyb;
  627.  
  628.     if (dev >= nasy)
  629.         return -1;
  630.  
  631.     asy[dev].speed = speed;
  632.  
  633.     if (ioctl(asy[dev].fd,TCGETA,&sgttyb) < 0) {
  634.         perror(asy[dev].tty);
  635.         return -1;
  636.     }
  637.  
  638.     sgttyb.c_cflag &= ~CBAUD;
  639.  
  640.     switch ((unsigned)speed) {
  641.     case 0:
  642.         sgttyb.c_cflag |= B0;
  643.         break;
  644.     case 50:
  645.         sgttyb.c_cflag |= B50;
  646.         break;
  647.     case 75:
  648.         sgttyb.c_cflag |= B75;
  649.         break;
  650.     case 110:
  651.         sgttyb.c_cflag |= B110;
  652.         break;
  653.     case 134:
  654.         sgttyb.c_cflag |= B134;
  655.         break;
  656.     case 150:
  657.         sgttyb.c_cflag |= B150;
  658.         break;
  659.     case 200:
  660.         sgttyb.c_cflag |= B200;
  661.         break;
  662.     case 300:
  663.         sgttyb.c_cflag |= B300;
  664.         break;
  665.     case 600:
  666.         sgttyb.c_cflag |= B600;
  667.         break;
  668.     case 1200:
  669.         sgttyb.c_cflag |= B1200;
  670.         break;
  671.     case 1800:
  672.         sgttyb.c_cflag |= B1800;
  673.         break;
  674.     case 2400:
  675.         sgttyb.c_cflag |= B2400;
  676.         break;
  677.     case 4800:
  678.         sgttyb.c_cflag |= B4800;
  679.         break;
  680.     case 9600:
  681.         sgttyb.c_cflag |= B9600;
  682.         break;
  683.     case 19200:
  684.         sgttyb.c_cflag |= B19200;
  685.         break;
  686.     case 38400:
  687.         sgttyb.c_cflag |= B38400;
  688.         break;
  689.     default:
  690.         printf("asy_speed: Unknown speed (%d)\n",speed);
  691.         break;
  692.     }
  693.  
  694.     if (ioctl(asy[dev].fd,TCSETAW,&sgttyb) < 0) {
  695.         perror(asy[dev].tty);
  696.         return -1;
  697.     }
  698.  
  699.     return 0;
  700. }
  701. /* Send a buffer to serial transmitter */
  702. asy_output(dev,buf,cnt)
  703. unsigned dev;
  704. char *buf;
  705. unsigned short cnt;
  706. {
  707. #ifdef DEBUG
  708.     int i;
  709.  
  710.     printf("asy_output(%d,%lx,%d):",dev,buf,cnt);
  711.     for (i = 0; i < cnt; i++)
  712.         printf(" %02x",uchar(buf[i]));
  713.  
  714.     printf("\n");
  715. #endif
  716.  
  717. #ifdef SELECT
  718.     prg_busy = 3;
  719. #endif
  720.  
  721.     if (dev >= nasy || !stxrdy(dev))
  722.         return -1;
  723.  
  724.     if (write(asy[dev].fd,buf,cnt) < cnt)
  725.         return -1;
  726.  
  727.     return 0;
  728. }
  729. /* Receive characters from asynch line
  730.  * Returns count of characters read
  731.  */
  732. int16
  733. asy_recv(dev,buf,cnt)
  734. int16 dev;
  735. char *buf;
  736. unsigned cnt;
  737. {
  738.     register struct asy *ap;
  739.     unsigned tot = 0;
  740.     int r;
  741.  
  742.     ap = &asy[dev];
  743.  
  744.     /* fill the read ahead buffer */
  745.     if(ap->cnt == 0) {
  746. #ifdef SELECT
  747.         if (FD_ISSET(ap->fd,&port_set) && !FD_ISSET(ap->fd,&read_set))
  748.             return 0;    /* select() indicates nothing there */
  749.  
  750.         FD_CLR(ap->fd,&read_set);
  751. #endif
  752.  
  753.         ap->data = ap->buf;
  754.         if ((r = read(ap->fd,ap->data,ap->bufsize)) <= 0)
  755.             return 0;
  756.  
  757.         ap->cnt = r;
  758.  
  759. #ifdef DEBUG
  760.         printf("asy_recv: read(%d) ",ap->cnt);
  761.         for (r = 0; r < ap->cnt; r++)
  762.             printf(" %02x",uchar(ap->data[r]));
  763.  
  764.         printf("\n");
  765. #endif
  766.     }
  767.     /* fetch what you need with no system call overhead */
  768.     if(cnt == 1) {        /* single byte copy, do it here */
  769.         *buf = *ap->data++;
  770.         ap->cnt--;
  771.         tot++;
  772.     } else {        /* multi-byte copy, left memcpy do the work */
  773.         r = min(cnt,ap->cnt);
  774.         memcpy(buf,ap->data,r);
  775.         ap->cnt -= r;
  776.         ap->data += r;
  777.         tot += r;
  778.     }
  779.  
  780.     return (tot);
  781. }
  782. int
  783. stxrdy(dev)
  784. int16 dev;
  785. {
  786. #ifdef SELECT
  787.     struct timeval timeout;
  788.     fd_set write_set;
  789.     int fd;
  790.  
  791.     fd = asy[dev].fd;        /* the fd we want to check */
  792.  
  793.     if (FD_ISSET(fd,&port_set))    /* select() on this device? */
  794.     {
  795.         FD_ZERO(&write_set);    /* write_fd = only that fd */
  796.         FD_SET(fd,&write_set);
  797.         read_set = port_set;    /* read: all valid ports */
  798.         timeout.tv_sec = timeout.tv_usec = 0;
  799.  
  800.         if (select(maxfd,&read_set,&write_set,NULL,&timeout) >= 0 &&
  801.             !FD_ISSET(fd,&write_set))
  802.             return 0;    /* not ready */
  803.     }
  804. #endif
  805. #if 0
  806.     ioctl(asy[dev].fd,TCSBRK,1);    /* wait for output to drain */
  807. #endif
  808.     return 1;
  809. }
  810.  
  811. /* find substring in another string */
  812.  
  813. char *strstr (s,f)
  814.     char *s,*f;
  815. {
  816.     char *p;
  817.  
  818.     while ((p = strchr(s,*f)) != NULLCHAR)
  819.     {
  820.         if (!strncmp(p,f,strlen(f)))
  821.             return p;
  822.  
  823.         s = p + 1;
  824.     }
  825.  
  826.     return p;
  827. }
  828.  
  829. #if (defined(M_I86MM))
  830. /* Convert a pointer to a long integer, so that it can be printed in a
  831.    compiler- and system-independent way.
  832.    This function currently assumes that pointers are 16-bit (int) size.
  833.  */
  834. long ptr2long (p)
  835. char *p;
  836. {
  837.     unsigned int rv = (unsigned int) p;
  838.  
  839.     return (long) rv;
  840. }
  841. #endif
  842.  
  843. /* interrupt disable and enable have no real meaning here */
  844.  
  845. char disable ()
  846.  
  847. {
  848.     return 0;
  849. }
  850.  
  851. void restore (ps)
  852.     char ps;
  853.  
  854. {
  855. }
  856.  
  857. /* this routine is supposed to give control to the system until something */
  858. /* is to be done.  when select is unusable, wait a short period    */
  859.  
  860. void eihalt ()
  861.  
  862. {
  863. #ifdef SELECT
  864.     prg_busy &= ~1;                /* apparently not active... */
  865.  
  866.     if (maxfd > 0)                /* select() supported? */
  867.         return;                /* then no reason to wait */
  868. #endif
  869.  
  870.     nap(100L);                /* when no select(), nap() */
  871. }
  872. ə